package org.robot.scm.platform.schedule;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpUtil;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.robot.scm.infra.LocalCacheHelper;
import org.robot.scm.platform.AbstractMonitor;
import org.robot.scm.platform.AbstractSchedule;
import org.robot.scm.pojos.config.BaseConfig;
import org.robot.scm.pojos.enums.MessageTypeEnum;
import org.robot.scm.pojos.enums.PlatformEnum;
import org.robot.scm.pojos.platform.FuturesContracts;
import org.robot.scm.pojos.platform.FuturesContractsBaseNotify;
import org.robot.scm.utils.DateTool;
import org.robot.scm.utils.SendNoticeHelper;
import org.robot.scm.utils.StreamUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * 期货合约数据
 *
 * @Author : Awn create on 2025/5/19 15:26
 */
@Slf4j
public class FuturesContractsJob extends AbstractSchedule {

    @Override
    public void handle() {
        String thisDay = new SimpleDateFormat("MM月dd日").format(new Date());
        String yearMonth = new SimpleDateFormat("yyyyMM").format(new Date());
        String day = new SimpleDateFormat("dd").format(new Date());

        // IH - 上证50
        String ihUrl = String.format("http://www.cffex.com.cn/sj/ccpm/%s/%s/%s.xml", yearMonth, day, "IH");
        String ihXml = HttpUtil.get(ihUrl);
        if (ihXml.contains("302 Found")) {
            LocalCacheHelper.put(FuturesContractsJob.class.getName(), DateTool.currentDate());
            log.info("上证50期货数据尚未更新");
            return;
        }
        List<FuturesContracts> ihContracts = convertXmlToList(ihXml);

        // 中信多单
        List<FuturesContracts> zxIhPlus = StreamUtils.filter(ihContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 中信空单
        List<FuturesContracts> zxIhMinus = StreamUtils.filter(ihContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 2);
        // 其他多单
        List<FuturesContracts> otherIhPlus = StreamUtils.filter(ihContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 其他空单
        List<FuturesContracts> otherIhMinus = StreamUtils.filter(ihContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 2);

        //中信净值
        int zxIhNetValue = StreamUtils.sumToInt(zxIhMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(zxIhPlus, FuturesContracts::getValue);
        int zxIhYestValue = StreamUtils.sumToInt(zxIhMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(zxIhPlus, FuturesContracts::getValueChange);

        // 其他净值
        int otherIhNetValue = StreamUtils.sumToInt(otherIhMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(otherIhPlus, FuturesContracts::getValue);
        int otherIhYestValue = StreamUtils.sumToInt(otherIhMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(otherIhPlus, FuturesContracts::getValueChange);

        // IF - 沪深300
        String ifUrl = String.format("http://www.cffex.com.cn/sj/ccpm/%s/%s/%s.xml", yearMonth, day, "IF");
        String ifXml = HttpUtil.get(ifUrl);
        if (ifXml.contains("302 Found")) {
            log.info("沪深300期货数据尚未更新");
            return;
        }
        List<FuturesContracts> ifContracts = convertXmlToList(ifXml);

        // 中信多单
        List<FuturesContracts> zxIfPlus = StreamUtils.filter(ifContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 中信空单
        List<FuturesContracts> zxIfMinus = StreamUtils.filter(ifContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 2);
        // 其他多单
        List<FuturesContracts> otherIfPlus = StreamUtils.filter(ifContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 其他空单
        List<FuturesContracts> otherIfMinus = StreamUtils.filter(ifContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 2);
        // 中信净值
        int zxIfNetValue = StreamUtils.sumToInt(zxIfMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(zxIfPlus, FuturesContracts::getValue);
        int zxIfYestValue = StreamUtils.sumToInt(zxIfMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(zxIfPlus, FuturesContracts::getValueChange);

        // 其他净值
        int otherIfNetValue = StreamUtils.sumToInt(otherIfMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(otherIfPlus, FuturesContracts::getValue);
        int otherIfYestValue = StreamUtils.sumToInt(otherIfMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(otherIfPlus, FuturesContracts::getValueChange);

        // IC - 中证500
        String icUrl = String.format("http://www.cffex.com.cn/sj/ccpm/%s/%s/%s.xml", yearMonth, day, "IC");
        String icXml = HttpUtil.get(icUrl);
        if (icXml.contains("302 Found")) {
            log.info("中证500期货数据尚未更新");
            return;
        }
        List<FuturesContracts> icContracts = convertXmlToList(icXml);

        // 中信多单
        List<FuturesContracts> zxIcPlus = StreamUtils.filter(icContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 中信空单
        List<FuturesContracts> zxIcMinus = StreamUtils.filter(icContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 2);
        // 其他多单
        List<FuturesContracts> otherIcPlus = StreamUtils.filter(icContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 其他空单
        List<FuturesContracts> otherIcMinus = StreamUtils.filter(icContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 2);

        // 中信净值
        int zxIcNetValue = StreamUtils.sumToInt(zxIcMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(zxIcPlus, FuturesContracts::getValue);
        int zxIcYestValue = StreamUtils.sumToInt(zxIcMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(zxIcPlus, FuturesContracts::getValueChange);

        // 其他净值
        int otherIcNetValue = StreamUtils.sumToInt(otherIcMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(otherIcPlus, FuturesContracts::getValue);
        int otherIcYestValue = StreamUtils.sumToInt(otherIcMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(otherIcPlus, FuturesContracts::getValueChange);

        // IM - 中证1000
        String imUrl = String.format("http://www.cffex.com.cn/sj/ccpm/%s/%s/%s.xml", yearMonth, day, "IM");
        String imXml = HttpUtil.get(imUrl);
        if (imXml.contains("302 Found")) {
            log.info("中证1000期货数据尚未更新");
            return;
        }
        List<FuturesContracts> imContracts = convertXmlToList(imXml);
        // 中信多单
        List<FuturesContracts> zxImPlus = StreamUtils.filter(imContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 中信空单
        List<FuturesContracts> zxImMinus = StreamUtils.filter(imContracts, e -> e.getInstitutionsId().equals("0018") && e.getDataType() == 2);
        // 其他多单
        List<FuturesContracts> otherImPlus = StreamUtils.filter(imContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 1);
        // 其他空单
        List<FuturesContracts> otherImMinus = StreamUtils.filter(imContracts, e -> !e.getInstitutionsId().equals("0018") && e.getDataType() == 2);

        // 中信净值
        int zxImNetValue = StreamUtils.sumToInt(zxImMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(zxImPlus, FuturesContracts::getValue);
        int zxImYestValue = StreamUtils.sumToInt(zxImMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(zxImPlus, FuturesContracts::getValueChange);

        // 其他净值
        int otherImNetValue = StreamUtils.sumToInt(otherImMinus, FuturesContracts::getValue) - StreamUtils.sumToInt(otherImPlus, FuturesContracts::getValue);
        int otherImYestValue = StreamUtils.sumToInt(otherImMinus, FuturesContracts::getValueChange) - StreamUtils.sumToInt(otherImPlus, FuturesContracts::getValueChange);

        int zxAllYestValue = zxIhYestValue + zxIfYestValue + zxIcYestValue + zxImYestValue;
        int otherAllYestValue = otherIhYestValue + otherIfYestValue + otherIcYestValue + otherImYestValue;

//        printValueLog(zxAllYestValue, otherAllYestValue, zxIhNetValue, zxIhYestValue, zxIfNetValue, zxIfYestValue, zxIcNetValue, zxIcYestValue, zxImNetValue, zxImYestValue,
//                otherIhNetValue, otherIhYestValue, otherIfNetValue, otherIfYestValue, otherIcNetValue, otherIcYestValue, otherImNetValue, otherImYestValue);

        List<String> htmlLines = FileUtil.readLines(new File(cronConfig().getNoticeSrc()), StandardCharsets.UTF_8);
        StringBuilder builder = new StringBuilder();

        for (String line : htmlLines) {
            builder.append(line
                    .replace("${allYestValue}", String.format("增加%s%s手", (zxAllYestValue + otherAllYestValue) > 0 ? "空单" : "多单", Math.abs(zxAllYestValue + otherAllYestValue)))
                    .replace("${allYestValueStatus}", (zxAllYestValue + otherAllYestValue) > 0 ? "status-red" : "status-green")

                    .replace("${zxAllYestValueStatus}", zxAllYestValue > 0 ? "status-red" : "status-green")

                    .replace("${zxIhNetValue}", formatVolume(zxIhNetValue))
                    .replace("${zxIhYestValueStatus}", zxIhYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${zxIhYestValue}", zxIhYestValue > 0 ? "+" + formatVolume(zxIhYestValue) : formatVolume(zxIhYestValue))

                    .replace("${zxIfNetValue}", formatVolume(zxIfNetValue))
                    .replace("${zxIfYestValueStatus}", zxIfYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${zxIfYestValue}", zxIfYestValue > 0 ? "+" + formatVolume(zxIfYestValue) : formatVolume(zxIfYestValue))

                    .replace("${zxIcNetValue}", formatVolume(zxIcNetValue))
                    .replace("${zxIcYestValueStatus}", zxIcYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${zxIcYestValue}", zxIcYestValue > 0 ? "+" + formatVolume(zxIcYestValue) : formatVolume(zxIcYestValue))

                    .replace("${zxImNetValue}", formatVolume(zxImNetValue))
                    .replace("${zxImYestValueStatus}", zxImYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${zxImYestValue}", zxImYestValue > 0 ? "+" + formatVolume(zxImYestValue) : formatVolume(zxImYestValue))

                    .replace("${zxAllYestValue}", String.format("净增加%s%s手", zxAllYestValue > 0 ? "空单" : "多单", Math.abs(zxAllYestValue)))

                    .replace("${otherAllYestValueStatus}", otherAllYestValue > 0 ? "status-red" : "status-green")

                    .replace("${otherIhNetValue}", formatVolume(otherIhNetValue))
                    .replace("${otherIhYestValueStatus}", otherIhYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${otherIhYestValue}", otherIhYestValue > 0 ? "+" + formatVolume(otherIhYestValue) : formatVolume(otherIhYestValue))

                    .replace("${otherIfNetValue}", formatVolume(otherIfNetValue))
                    .replace("${otherIfYestValueStatus}", otherIfYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${otherIfYestValue}", otherIfYestValue > 0 ? "+" + formatVolume(otherIfYestValue) : formatVolume(otherIfYestValue))

                    .replace("${otherIcNetValue}", formatVolume(otherIcNetValue))
                    .replace("${otherIcYestValueStatus}", otherIcYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${otherIcYestValue}", otherIcYestValue > 0 ? "+" + formatVolume(otherIcYestValue) : formatVolume(otherIcYestValue))

                    .replace("${otherImNetValue}", formatVolume(otherImNetValue))
                    .replace("${otherImYestValueStatus}", otherImYestValue > 0 ? "change-negative" : "change-positive")
                    .replace("${otherImYestValue}", otherImYestValue > 0 ? "+" + formatVolume(otherImYestValue) : formatVolume(otherImYestValue))

                    .replace("${otherAllYestValue}", String.format("净增加%s%s手", otherAllYestValue > 0 ? "空单" : "多单", Math.abs(otherAllYestValue)))
                    .replace("${updateTime}", yearMonth + day)
            );
        }

        FuturesContractsBaseNotify notice = new FuturesContractsBaseNotify();
        notice.setMessageType(MessageTypeEnum.HTML);
        notice.setHtmlMessage(builder.toString());
        notice.setTextMessage(buildTextMessage(zxAllYestValue, otherAllYestValue));
        notice.setTopic(thisDay + "股指机构动向");

        BaseConfig config = new BaseConfig(AbstractMonitor.mainConfig, AbstractMonitor.mainConfig.getPlatform(PlatformEnum.SCHEDULE));
        SendNoticeHelper.sendNotice(config, notice, PlatformEnum.SCHEDULE);
    }

    private void printValueLog(int zxAllYestValue, int otherAllYestValue, int zxIhNetValue, int zxIhYestValue, int zxIfNetValue, int zxIfYestValue, int zxIcNetValue, int zxIcYestValue, int zxImNetValue, int zxImYestValue,
            int otherIhNetValue, int otherIhYestValue, int otherIfNetValue, int otherIfYestValue, int otherIcNetValue, int otherIcYestValue, int otherImNetValue, int otherImYestValue) {
        log.info("中信净增加{}{}手", zxAllYestValue > 0 ? "空单" : "多单", Math.abs(zxAllYestValue));
        log.info("上证50 => 净空单: {}, 对比前日: {}",
                zxIhNetValue,
                zxIhYestValue
        );
        log.info("沪深300 => 净空单: {}, 对比前日: {}",
                zxIfNetValue,
                zxIfYestValue
        );
        log.info("中证500 => 净空单: {}, 对比前日: {}",
                zxIcNetValue,
                zxIcYestValue
        );
        log.info("中证1000 => 净空单: {}, 对比前日: {}",
                zxImNetValue,
                zxImYestValue
        );
        log.info("");
        log.info("其他净增加{}{}手", otherAllYestValue > 0 ? "空单" : "多单", Math.abs(otherAllYestValue));
        log.info("上证50 => 净空单: {}, 对比前日: {}",
                otherIhNetValue,
                otherIhYestValue
        );
        log.info("沪深300 => 净空单: {}, 对比前日: {}",
                otherIfNetValue,
                otherIfYestValue
        );
        log.info("中证500 => 净空单: {}, 对比前日: {}",
                otherIcNetValue,
                otherIcYestValue
        );
        log.info("中证1000 => 净空单: {}, 对比前日: {}",
                otherImNetValue,
                otherImYestValue
        );
        log.info("合计净增加{}{}手", (zxAllYestValue + otherAllYestValue) > 0 ? "空单" : "多单", Math.abs(zxAllYestValue + otherAllYestValue));
    }

    private String buildTextMessage(int zxAllYestValue, int otherAllYestValue) {
        return String.format("%s 中信净增加%s%s手\n%s 其他净增加%s%s手\n%s 合计净增加%s%s手",
                zxAllYestValue > 0 ? "\uD83D\uDD34" : "\uD83D\uDFE2",
                zxAllYestValue > 0 ? "空单" : "多单", Math.abs(zxAllYestValue),
                otherAllYestValue > 0 ? "\uD83D\uDD34" : "\uD83D\uDFE2",
                otherAllYestValue > 0 ? "空单" : "多单", Math.abs(otherAllYestValue),
                (zxAllYestValue + otherAllYestValue) > 0 ? "\uD83D\uDD34" : "\uD83D\uDFE2",
                (zxAllYestValue + otherAllYestValue) > 0 ? "空单" : "多单", Math.abs(zxAllYestValue + otherAllYestValue));
    }


    @Override
    public String getName() {
        return "futuresContractsJob";
    }

    private String formatVolume(Integer volume) {
        if (volume == null) {
            return "0";
        }
        DecimalFormat df = new DecimalFormat("#,###");
        return df.format(volume);
    }

    /**
     * 将XML字符串转换为List<FuturesContracts>
     *
     * @param xml XML字符串
     * @return FuturesContracts列表
     */
    private List<FuturesContracts> convertXmlToList(String xml) {
        List<FuturesContracts> resultList = new ArrayList<>();
        try {
            Document document = XmlUtil.readXML(xml);
            NodeList dataNodes = document.getElementsByTagName("data");
            for (int i = 0; i < dataNodes.getLength(); i++) {
                Element dataElement = (Element) dataNodes.item(i);
                resultList.add(FuturesContracts.builder()
                        .institutionsId(getElementText(dataElement, "partyid"))
                        .institutionsName(getElementText(dataElement, "shortname"))
                        .instrumentName(getElementText(dataElement, "instrumentid"))
                        .tradingDay(getElementText(dataElement, "tradingday"))
                        .dataType(Integer.parseInt(getElementText(dataElement, "datatypeid")))
                        .value(Integer.parseInt(getElementText(dataElement, "volume")))
                        .valueChange(Integer.parseInt(getElementText(dataElement, "varvolume")))
                        .build());
            }
        } catch (Exception e) {
            log.error("XML转换失败", e);
        }
        return resultList;
    }

    /**
     * 获取元素文本内容
     *
     * @param parent  父元素
     * @param tagName 标签名
     * @return 文本内容
     */
    private String getElementText(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            return nodeList.item(0).getTextContent();
        }
        return "";
    }

}
